package com.example.controller;

import ch.qos.logback.core.Context;
//import cn.hutool.http.HttpRequest;
//import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.example.exception.BaseException;
import com.example.model.api.Result;
import com.example.utils.JSON;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsent;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.net.http.HttpClient;
import java.net.http.HttpResponse;
import java.security.Principal;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
//import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URI;
//import java.net.http.HttpClient;


/**
 * @author Daniel Garnier-Moiroux
 */
@Controller
public class AuthorizationConsentController {
    @Autowired
    private RestTemplate restTemplate;
    private final RegisteredClientRepository registeredClientRepository;
    private final OAuth2AuthorizationConsentService authorizationConsentService;
    @Autowired
    private Environment environment;

    public AuthorizationConsentController(RegisteredClientRepository registeredClientRepository,
                                          OAuth2AuthorizationConsentService authorizationConsentService) {
        this.registeredClientRepository = registeredClientRepository;
        this.authorizationConsentService = authorizationConsentService;
    }

    @GetMapping("/user/token")
    public Result<Map<String, Object>> usertoken(@RequestParam Map<String, Object> mapParams) {
        String code = (String) mapParams.get("code");
        HashMap<String, Object> objectHashMap = new HashMap<>();
        objectHashMap.put("grant_type", AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
        objectHashMap.put("code", code);
        objectHashMap.put("redirect_uri", "http://localhost:7070/auth/redirect_uris/callback");
        String body = cn.hutool.http.HttpRequest.post(environment.getProperty("spring.security.oauth2.resourceserver.jwt.issuer-uri") + "/oauth2/token")
                .basicAuth("zy1904807846818746369", "44af39b11e6ff03e303a21ab2c946faf")
                .form(objectHashMap)
                .execute().body();
        return new Result<Map<String, Object>>().ok(JSONUtil.toBean(body, Map.class));
    }

    @GetMapping("/gitee-callback")
    public String giteecallback() {
        return "gitee-callback";
    }

    @GetMapping("/callback")
    public String callbackaaa() {
        return "callback";
    }

    @GetMapping("public/login/gitee/config")
    @ResponseBody
    public Result<Map<String, Object>> config() {
        Map<String, Object> map = new HashMap<>();
        map.put("clientId", "dd474a063d7bbf1317857d4a0ce2b8b6b7d13ff98074fd76c30f265d06c82089");
        map.put("redirectUri", "http://localhost:7070/auth/gitee-callback");
        return new Result<Map<String, Object>>().ok(map);
    }

    @PostMapping("/public/user/login/gitee")
    @ResponseBody
    public Result<Map<String, Object>> getTokenByCode(@RequestParam Map<String, Object> params) {
        String code = (String) params.get("code");
        String url = "https://gitee.com/oauth/token?grant_type=authorization_code"
                + "&code=" + code
                + "&client_id=" + "dd474a063d7bbf1317857d4a0ce2b8b6b7d13ff98074fd76c30f265d06c82089"
                + "&redirect_uri=" + "http://localhost:7070/auth/gitee-callback"
                + "&client_secret=" + "362e82a2dac2a71ac566cbf3b4281417d4dc73cdebce8252f515fee79145d3ed";
        String responseJson = sendPostRequest(url, null);
        Map<String, Object> responseMap = JSON.parseToMap(responseJson);
        Object accessToken = responseMap.get("access_token");
        if (accessToken == null) {
            throw new BaseException("错误");
        }
        Map<String, Object> thirdUserInfo = getThirdUserInfo(accessToken.toString());
        return new Result<Map<String, Object>>().ok(thirdUserInfo);
    }

    @PostMapping("/public/user/login/messages")
    @ResponseBody
    public Result<Map<String, Object>> getTokenBmessagesyCode(@RequestParam Map<String, Object> params) {
        String code = (String) params.get("code");
        HashMap<String, Object> objectHashMap = new HashMap<>();
        objectHashMap.put("grant_type", AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
        objectHashMap.put("code", code);
        objectHashMap.put("redirect_uri", "http://localhost:7070/sys/index-callback");
        String body = HttpRequest.post("http://localhost:9526/auth/oauth2/token")
                .basicAuth("zy1904807846818746369", "44af39b11e6ff03e303a21ab2c946faf")
                .form(objectHashMap)
                .execute().body();
        return new Result<Map<String, Object>>().ok(JSONUtil.toBean(body, Map.class));
    }

    public Map<String, Object> getThirdUserInfo(String token) {
        // {"id":1483966,"login":"用户名"}
        String responseJson = sendGetRequest("https://gitee.com/api/v5/user?access_token=" + token);
        Map<String, Object> responseMap = JSON.parseToMap(responseJson);
        Object openId = responseMap.get("id");
        if (openId == null) {
            return null;
        }

        HashMap<String, Object> thirdUser = new HashMap<>();
        thirdUser.put("openId", openId);
        thirdUser.put("nickname", responseMap.get("login"));
        return thirdUser;
    }


    public String sendPostRequest(String url, Map<String, Object> body) {
        // 请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 创建HttpEntity对象
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(body, headers);
        // 发送POST请求
        try {
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity,
                    String.class);
            // 返回响应体
            return response.getBody();
        } catch (HttpClientErrorException e) {
            return e.getResponseBodyAsString();
        }
    }

    public String sendGetRequest(String url) {
        // 请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 创建HttpEntity对象
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(headers);
        // 发送GET请求
        try {
            ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, requestEntity,
                    String.class);
            // 返回响应体
            return response.getBody();
        } catch (HttpClientErrorException e) {
            return e.getResponseBodyAsString();
        }
    }


    @RequestMapping("/redirect_uris/callback")
    public String redirect_uris_callback() {
        return "callback";
    }

    // http://localhost:9526/oauth2/authorize?client_id=password-client&redirect_uri=http://127.0.0.1:8080/authorized&response_type=code&scope=message.read
    // http://localhost:9526/oauth2/authorize?client_id=messaging-client&redirect_uri=http://127.0.0.1:8080/authorized&response_type=code&scope=message.write
    @GetMapping(value = "/oauth2/consent")
    public String consent(Principal principal, Model model,
                          @RequestParam(OAuth2ParameterNames.CLIENT_ID) String clientId,
                          @RequestParam(OAuth2ParameterNames.SCOPE) String scope,
                          @RequestParam(OAuth2ParameterNames.STATE) String state,
                          @RequestParam(name = OAuth2ParameterNames.USER_CODE, required = false) String userCode) {

        // Remove scopes that were already approved
        Set<String> scopesToApprove = new HashSet<>();
        Set<String> previouslyApprovedScopes = new HashSet<>();
        Set<String> authorizedScopes;
        RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);
        authorizedScopes = registeredClient.getScopes();

        for (String requestedScope : StringUtils.delimitedListToStringArray(scope, " ")) {
            if (OidcScopes.OPENID.equals(requestedScope)) {
                continue;
            }
            if (authorizedScopes.contains(requestedScope)) {
                previouslyApprovedScopes.add(requestedScope);
            } else {
                scopesToApprove.add(requestedScope);
            }
        }
//		user_info,openid,profile,message.read
//		scopesToApprove.add("user_info");
        scopesToApprove.add("openid");
//		scopesToApprove.add("profile");
//		scopesToApprove.add("message.read");

        model.addAttribute("clientId", clientId);
        model.addAttribute("state", state);
        model.addAttribute("scopes", withDescription(scopesToApprove));
        model.addAttribute("previouslyApprovedScopes", withDescription(previouslyApprovedScopes));
        model.addAttribute("principalName", "principal.getName()");
        model.addAttribute("userCode", userCode);
        if (StringUtils.hasText(userCode)) {
            model.addAttribute("requestURI", "/oauth2/device_verification");
        } else {
            model.addAttribute("requestURI", "http://localhost:7070/auth/meassage-callback");
//            model.addAttribute("requestURI", "http://localhost:9111/client/login/oauth2/code/password-client-authorization-code");
        }

        return "consent";
    }

    private static Set<ScopeWithDescription> withDescription(Set<String> scopes) {
        Set<ScopeWithDescription> scopeWithDescriptions = new HashSet<>();
        for (String scope : scopes) {
            scopeWithDescriptions.add(new ScopeWithDescription(scope));

        }
        return scopeWithDescriptions;
    }

    public static class ScopeWithDescription {
        private static final String DEFAULT_DESCRIPTION = "UNKNOWN SCOPE - We cannot provide information about this permission, use caution when granting this.";
        private static final Map<String, String> scopeDescriptions = new HashMap<>();

        static {
            scopeDescriptions.put(
                    OidcScopes.PROFILE,
                    "This application will be able to read your profile information."
            );
            scopeDescriptions.put(
                    "message.read",
                    "This application will be able to read your message."
            );
            scopeDescriptions.put(
                    "message.write",
                    "This application will be able to add new messages. It will also be able to edit and delete existing messages."
            );
            scopeDescriptions.put(
                    "other.scope",
                    "This is another scope example of a scope description."
            );
        }

        public final String scope;
        public final String description;

        ScopeWithDescription(String scope) {
            this.scope = scope;
            this.description = scopeDescriptions.getOrDefault(scope, DEFAULT_DESCRIPTION);
        }
    }

}
